using FluffyUnderware.DevTools;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace FluffyUnderware.Curvy.Generator
{
	public abstract class SplineInputModuleBase : CGModule
	{
		[Tab("General")]
		[SerializeField]
		[Tooltip("Makes this module use the cached approximations of the spline's positions and tangents")]
		private bool m_UseCache;

		[Tab("Range")]
		[SerializeField]
		protected CurvySplineSegment m_StartCP;

		[FieldCondition("m_StartCP", null, true, ActionAttribute.ActionEnum.Show, null, ActionAttribute.ActionPositionEnum.Below, Action = ActionAttribute.ActionEnum.Enable)]
		[SerializeField]
		protected CurvySplineSegment m_EndCP;

		public bool UseCache
		{
			get
			{
				return m_UseCache;
			}
			set
			{
				if (m_UseCache != value)
				{
					m_UseCache = value;
				}
				base.Dirty = true;
			}
		}

		public CurvySplineSegment StartCP
		{
			get
			{
				return m_StartCP;
			}
			set
			{
				if (m_StartCP != value)
				{
					m_StartCP = value;
					ValidateStartAndEndCps();
				}
				base.Dirty = true;
			}
		}

		public CurvySplineSegment EndCP
		{
			get
			{
				return m_EndCP;
			}
			set
			{
				if (m_EndCP != value)
				{
					m_EndCP = value;
					ValidateStartAndEndCps();
				}
				base.Dirty = true;
			}
		}

		protected override void OnEnable()
		{
			base.OnEnable();
			Properties.MinWidth = 250f;
		}

		protected abstract void ValidateStartAndEndCps();

		protected float getPathLength(CurvySpline spline)
		{
			if (!spline)
			{
				return 0f;
			}
			if ((bool)StartCP && (bool)EndCP)
			{
				return EndCP.Distance - StartCP.Distance;
			}
			return spline.Length;
		}

		protected bool getPathClosed(CurvySpline spline)
		{
			if (!spline || !spline.Closed)
			{
				return false;
			}
			return EndCP == null;
		}

		protected CGData GetSplineData(CurvySpline spline, bool fullPath, CGDataRequestRasterization raster, CGDataRequestMetaCGOptions options)
		{
			if (spline == null || spline.Count == 0)
			{
				return null;
			}
			List<ControlPointOption> list = new List<ControlPointOption>();
			int initialMaterialID = 0;
			float initialMaxStep = float.MaxValue;
			CGShape data = (!fullPath) ? new CGShape() : new CGPath();
			float startDist;
			float num;
			if ((bool)StartCP)
			{
				float pathLength = getPathLength(spline);
				startDist = StartCP.Distance + pathLength * raster.Start;
				num = StartCP.Distance + pathLength * (raster.Start + raster.RasterizedRelativeLength);
			}
			else
			{
				startDist = spline.Length * raster.Start;
				num = spline.Length * (raster.Start + raster.RasterizedRelativeLength);
			}
			float num2 = CurvySpline.CalculateSamplingPointsPerUnit(raster.Resolution, spline.MaxPointsPerUnit);
			float movedDistance = (num - startDist) / (raster.SplineAbsoluteLength * raster.RasterizedRelativeLength * num2);
			data.Length = num - startDist;
			float tf = spline.DistanceToTF(startDist);
			float startTF = tf;
			float num3 = (!(num > spline.Length) || !spline.Closed) ? spline.DistanceToTF(num) : (spline.DistanceToTF(num - spline.Length) + 1f);
			data.SourceIsManaged = IsManagedResource(spline);
			data.Closed = spline.Closed;
			data.Seamless = (spline.Closed && raster.RasterizedRelativeLength == 1f);
			if (data.Length == 0f)
			{
				return data;
			}
			if ((bool)options)
			{
				list = CGUtility.GetControlPointsWithOptions(options, spline, startDist, num, raster.Mode == CGDataRequestRasterization.ModeEnum.Optimized, out initialMaterialID, out initialMaxStep);
			}
			List<SamplePointUData> list2 = new List<SamplePointUData>();
			List<Vector3> pos = new List<Vector3>();
			List<float> relF = new List<float>();
			List<float> sourceF = new List<float>();
			List<Vector3> tan = new List<Vector3>();
			List<Vector3> up = new List<Vector3>();
			float curDist = startDist;
			Vector3 curTan = Vector3.zero;
			Vector3 item = Vector3.zero;
			List<int> list3 = new List<int>();
			int num4 = 100000;
			Vector3 curPos;
			switch (raster.Mode)
			{
			case CGDataRequestRasterization.ModeEnum.Even:
			{
				bool flag = false;
				SamplePointsMaterialGroup samplePointsMaterialGroup = new SamplePointsMaterialGroup(initialMaterialID);
				SamplePointsPatch item2 = new SamplePointsPatch(0);
				CurvyClamping clamping = data.Closed ? CurvyClamping.Loop : CurvyClamping.Clamp;
				while (curDist <= num && --num4 > 0)
				{
					tf = spline.DistanceToTF(spline.ClampDistance(curDist, clamping));
					curPos = ((!UseCache) ? spline.Interpolate(tf) : spline.InterpolateFast(tf));
					float num8 = (curDist - startDist) / data.Length;
					if (Mathf.Approximately(1f, num8))
					{
						num8 = 1f;
					}
					pos.Add(curPos);
					relF.Add(num8);
					sourceF.Add(curDist / spline.Length);
					if (fullPath)
					{
						curTan = ((!UseCache) ? spline.GetTangent(tf, curPos) : spline.GetTangentFast(tf));
						item = spline.GetOrientationUpFast(tf);
						tan.Add(curTan);
						up.Add(item);
					}
					if (flag)
					{
						pos.Add(curPos);
						relF.Add(num8);
						sourceF.Add(curDist / spline.Length);
						if (fullPath)
						{
							tan.Add(curTan);
							up.Add(item);
						}
						flag = false;
					}
					curDist += movedDistance;
					if (list.Count > 0)
					{
						float num9 = curDist;
						ControlPointOption controlPointOption24 = list[0];
						if (num9 >= controlPointOption24.Distance)
						{
							ControlPointOption controlPointOption25 = list[0];
							if (!controlPointOption25.UVEdge)
							{
								ControlPointOption controlPointOption26 = list[0];
								if (!controlPointOption26.UVShift)
								{
									goto IL_0547;
								}
							}
							List<SamplePointUData> list7 = list2;
							int count2 = pos.Count;
							ControlPointOption controlPointOption27 = list[0];
							bool uVEdge4 = controlPointOption27.UVEdge;
							ControlPointOption controlPointOption28 = list[0];
							float firstU4 = controlPointOption28.FirstU;
							ControlPointOption controlPointOption29 = list[0];
							list7.Add(new SamplePointUData(count2, uVEdge4, firstU4, controlPointOption29.SecondU));
							goto IL_0547;
						}
					}
					goto IL_06d5;
					IL_0547:
					ControlPointOption controlPointOption30 = list[0];
					curDist = controlPointOption30.Distance;
					ControlPointOption controlPointOption31 = list[0];
					int num10;
					if (!controlPointOption31.HardEdge)
					{
						ControlPointOption controlPointOption32 = list[0];
						if (controlPointOption32.MaterialID == samplePointsMaterialGroup.MaterialID)
						{
							if (options.CheckExtendedUV)
							{
								ControlPointOption controlPointOption33 = list[0];
								num10 = (controlPointOption33.UVEdge ? 1 : 0);
							}
							else
							{
								num10 = 0;
							}
							goto IL_05b0;
						}
					}
					num10 = 1;
					goto IL_05b0;
					IL_05b0:
					flag = ((byte)num10 != 0);
					if (flag)
					{
						item2.End = pos.Count;
						samplePointsMaterialGroup.Patches.Add(item2);
						int materialID2 = samplePointsMaterialGroup.MaterialID;
						ControlPointOption controlPointOption34 = list[0];
						if (materialID2 != controlPointOption34.MaterialID)
						{
							data.MaterialGroups.Add(samplePointsMaterialGroup);
							ControlPointOption controlPointOption35 = list[0];
							samplePointsMaterialGroup = new SamplePointsMaterialGroup(controlPointOption35.MaterialID);
						}
						item2 = new SamplePointsPatch(pos.Count + 1);
						ControlPointOption controlPointOption36 = list[0];
						if (!controlPointOption36.HardEdge)
						{
							list3.Add(pos.Count + 1);
						}
						ControlPointOption controlPointOption37 = list[0];
						if (!controlPointOption37.UVEdge)
						{
							ControlPointOption controlPointOption38 = list[0];
							if (!controlPointOption38.UVShift)
							{
								goto IL_06ce;
							}
						}
						List<SamplePointUData> list8 = list2;
						int vt3 = pos.Count + 1;
						ControlPointOption controlPointOption39 = list[0];
						bool uVEdge5 = controlPointOption39.UVEdge;
						ControlPointOption controlPointOption40 = list[0];
						float firstU5 = controlPointOption40.FirstU;
						ControlPointOption controlPointOption41 = list[0];
						list8.Add(new SamplePointUData(vt3, uVEdge5, firstU5, controlPointOption41.SecondU));
					}
					goto IL_06ce;
					IL_06d5:
					if (curDist > num && num8 < 1f)
					{
						curDist = num;
					}
					continue;
					IL_06ce:
					list.RemoveAt(0);
					goto IL_06d5;
				}
				if (num4 <= 0)
				{
					UnityEngine.Debug.LogError("[Curvy] He's dead, Jim! Deadloop in SplineInputModuleBase.GetSplineData (Even)! Please send a bug report!");
				}
				item2.End = pos.Count - 1;
				samplePointsMaterialGroup.Patches.Add(item2);
				if (data.Closed && !spline[0].GetMetadata<MetaCGOptions>(autoCreate: true).HardEdge)
				{
					list3.Add(0);
				}
				data.MaterialGroups.Add(samplePointsMaterialGroup);
				data.SourceF = sourceF.ToArray();
				data.F = relF.ToArray();
				data.Position = pos.ToArray();
				if (fullPath)
				{
					((CGPath)data).Direction = tan.ToArray();
					data.Normal = up.ToArray();
				}
				break;
			}
			case CGDataRequestRasterization.ModeEnum.Optimized:
			{
				bool flag = false;
				SamplePointsMaterialGroup samplePointsMaterialGroup = new SamplePointsMaterialGroup(initialMaterialID);
				SamplePointsPatch item2 = new SamplePointsPatch(0);
				float stepDist = movedDistance / spline.Length;
				float angleThreshold = raster.AngleThreshold;
				curPos = ((!UseCache) ? spline.Interpolate(tf) : spline.InterpolateFast(tf));
				curTan = ((!UseCache) ? spline.GetTangent(tf, curPos) : spline.GetTangentFast(tf));
				Action<float> action = delegate(float f)
				{
					sourceF.Add(curDist / spline.Length);
					pos.Add(curPos);
					relF.Add((curDist - startDist) / data.Length);
					if (fullPath)
					{
						tan.Add(curTan);
						up.Add(spline.GetOrientationUpFast(f));
					}
				};
				while (tf < num3 && num4-- > 0)
				{
					action(tf % 1f);
					float num6;
					if (list.Count > 0)
					{
						ControlPointOption controlPointOption = list[0];
						num6 = controlPointOption.TF;
					}
					else
					{
						num6 = num3;
					}
					float stopTF = num6;
					bool flag2 = MoveByAngleExt(spline, UseCache, ref tf, 0f, initialMaxStep, angleThreshold, out curPos, out curTan, out movedDistance, stopTF, data.Closed, stepDist);
					curDist += movedDistance;
					if (Mathf.Approximately(tf, num3) || tf > num3)
					{
						curDist = num;
						num3 = ((!data.Closed) ? Mathf.Clamp01(num3) : DTMath.Repeat(num3, 1f));
						curPos = ((!UseCache) ? spline.Interpolate(num3) : spline.InterpolateFast(num3));
						if (fullPath)
						{
							curTan = ((!UseCache) ? spline.GetTangent(num3, curPos) : spline.GetTangentFast(num3));
						}
						action(num3);
						break;
					}
					if (!flag2)
					{
						continue;
					}
					if (list.Count > 0)
					{
						ControlPointOption controlPointOption2 = list[0];
						if (!controlPointOption2.UVEdge)
						{
							ControlPointOption controlPointOption3 = list[0];
							if (!controlPointOption3.UVShift)
							{
								goto IL_0a7a;
							}
						}
						List<SamplePointUData> list4 = list2;
						int count = pos.Count;
						ControlPointOption controlPointOption4 = list[0];
						bool uVEdge = controlPointOption4.UVEdge;
						ControlPointOption controlPointOption5 = list[0];
						float firstU = controlPointOption5.FirstU;
						ControlPointOption controlPointOption6 = list[0];
						list4.Add(new SamplePointUData(count, uVEdge, firstU, controlPointOption6.SecondU));
						goto IL_0a7a;
					}
					action(tf);
					break;
					IL_0a7a:
					ControlPointOption controlPointOption7 = list[0];
					curDist = controlPointOption7.Distance;
					ControlPointOption controlPointOption8 = list[0];
					initialMaxStep = controlPointOption8.MaxStepDistance;
					ControlPointOption controlPointOption9 = list[0];
					int num7;
					if (!controlPointOption9.HardEdge)
					{
						ControlPointOption controlPointOption10 = list[0];
						if (controlPointOption10.MaterialID == samplePointsMaterialGroup.MaterialID)
						{
							if (options.CheckExtendedUV)
							{
								ControlPointOption controlPointOption11 = list[0];
								num7 = (controlPointOption11.UVEdge ? 1 : 0);
							}
							else
							{
								num7 = 0;
							}
							goto IL_0af4;
						}
					}
					num7 = 1;
					goto IL_0af4;
					IL_0c1b:
					list.RemoveAt(0);
					continue;
					IL_0c12:
					action(tf);
					goto IL_0c1b;
					IL_0af4:
					if (num7 != 0)
					{
						item2.End = pos.Count;
						samplePointsMaterialGroup.Patches.Add(item2);
						int materialID = samplePointsMaterialGroup.MaterialID;
						ControlPointOption controlPointOption12 = list[0];
						if (materialID != controlPointOption12.MaterialID)
						{
							data.MaterialGroups.Add(samplePointsMaterialGroup);
							ControlPointOption controlPointOption13 = list[0];
							samplePointsMaterialGroup = new SamplePointsMaterialGroup(controlPointOption13.MaterialID);
						}
						item2 = new SamplePointsPatch(pos.Count + 1);
						ControlPointOption controlPointOption14 = list[0];
						if (!controlPointOption14.HardEdge)
						{
							list3.Add(pos.Count + 1);
						}
						ControlPointOption controlPointOption15 = list[0];
						if (!controlPointOption15.UVEdge)
						{
							ControlPointOption controlPointOption16 = list[0];
							if (!controlPointOption16.UVShift)
							{
								goto IL_0c12;
							}
						}
						List<SamplePointUData> list5 = list2;
						int vt = pos.Count + 1;
						ControlPointOption controlPointOption17 = list[0];
						bool uVEdge2 = controlPointOption17.UVEdge;
						ControlPointOption controlPointOption18 = list[0];
						float firstU2 = controlPointOption18.FirstU;
						ControlPointOption controlPointOption19 = list[0];
						list5.Add(new SamplePointUData(vt, uVEdge2, firstU2, controlPointOption19.SecondU));
						goto IL_0c12;
					}
					goto IL_0c1b;
				}
				if (num4 <= 0)
				{
					UnityEngine.Debug.LogError("[Curvy] He's dead, Jim! Deadloop in SplineInputModuleBase.GetSplineData (Optimized)! Please send a bug report!");
				}
				item2.End = pos.Count - 1;
				samplePointsMaterialGroup.Patches.Add(item2);
				if (list.Count > 0)
				{
					ControlPointOption controlPointOption20 = list[0];
					if (controlPointOption20.UVShift)
					{
						List<SamplePointUData> list6 = list2;
						int vt2 = pos.Count - 1;
						ControlPointOption controlPointOption21 = list[0];
						bool uVEdge3 = controlPointOption21.UVEdge;
						ControlPointOption controlPointOption22 = list[0];
						float firstU3 = controlPointOption22.FirstU;
						ControlPointOption controlPointOption23 = list[0];
						list6.Add(new SamplePointUData(vt2, uVEdge3, firstU3, controlPointOption23.SecondU));
					}
				}
				if (data.Closed && !spline[0].GetMetadata<MetaCGOptions>(autoCreate: true).HardEdge)
				{
					list3.Add(0);
				}
				data.MaterialGroups.Add(samplePointsMaterialGroup);
				data.SourceF = sourceF.ToArray();
				data.F = relF.ToArray();
				data.Position = pos.ToArray();
				data.Bounds = spline.Bounds;
				if (fullPath)
				{
					((CGPath)data).Direction = tan.ToArray();
					data.Normal = up.ToArray();
				}
				break;
			}
			}
			data.Map = (float[])data.F.Clone();
			if (!fullPath)
			{
				data.RecalculateNormals(list3);
				if ((bool)options && options.CheckExtendedUV)
				{
					CalculateExtendedUV(spline, startTF, num3, list2, data);
				}
			}
			return data;
		}

		private static bool MoveByAngleExt(CurvySpline spline, bool useCache, ref float tf, float minDistance, float maxDistance, float maxAngle, out Vector3 pos, out Vector3 tan, out float movedDistance, float stopTF, bool loop, float stepDist)
		{
			minDistance = Mathf.Max(0f, minDistance);
			maxDistance = Mathf.Max(minDistance, maxDistance);
			if (!loop)
			{
				tf = Mathf.Clamp01(tf);
			}
			float tf2 = (!loop) ? tf : (tf % 1f);
			pos = ((!useCache) ? spline.Interpolate(tf2) : spline.InterpolateFast(tf2));
			tan = ((!useCache) ? spline.GetTangent(tf2, pos) : spline.GetTangentFast(tf2));
			Vector3 b = pos;
			Vector3 vector = tan;
			movedDistance = 0f;
			float num = 0f;
			int num2 = 0;
			if (stopTF < tf && loop)
			{
				stopTF += 1f;
			}
			while (tf < stopTF)
			{
				tf = Mathf.Min(stopTF, tf + stepDist);
				tf2 = ((!loop) ? tf : (tf % 1f));
				pos = ((!useCache) ? spline.Interpolate(tf2) : spline.InterpolateFast(tf2));
				tan = ((!useCache) ? spline.GetTangent(tf2, pos) : spline.GetTangentFast(tf2));
				movedDistance += (pos - b).magnitude;
				num += Vector3.Angle(vector, tan);
				if (tan == vector)
				{
					num2++;
				}
				if (movedDistance >= minDistance)
				{
					if (movedDistance >= maxDistance)
					{
						break;
					}
					if (num >= maxAngle)
					{
						num = 0f;
						break;
					}
					if (num2 > 0 && num > 0f)
					{
						break;
					}
				}
				b = pos;
				vector = tan;
			}
			return Mathf.Approximately(tf, stopTF);
		}

		private void CalculateExtendedUV(CurvySpline spline, float startTF, float endTF, List<SamplePointUData> ext, CGShape data)
		{
			MetaCGOptions metaCGOptions = findPreviousReferenceCPOptions(spline, startTF, out CurvySplineSegment cp);
			MetaCGOptions metaCGOptions2 = findNextReferenceCPOptions(spline, startTF, out CurvySplineSegment cp2);
			ext.Insert(0, new SamplePointUData(uv0: ((!(spline.FirstVisibleControlPoint == cp2)) ? ((data.SourceF[0] * spline.Length - cp.Distance) / (cp2.Distance - cp.Distance)) : ((data.SourceF[0] * spline.Length - cp.Distance) / (spline.Length - cp.Distance))) * (metaCGOptions2.FirstU - metaCGOptions.GetDefinedFirstU(0f)) + metaCGOptions.GetDefinedFirstU(0f), vt: 0, uvEdge: startTF == 0f && metaCGOptions.UVEdge, uv1: (startTF != 0f || !metaCGOptions.UVEdge) ? 0f : metaCGOptions.SecondU));
			SamplePointUData samplePointUData = ext[ext.Count - 1];
			if (samplePointUData.Vertex < data.Count - 1)
			{
				metaCGOptions = findPreviousReferenceCPOptions(spline, endTF, out cp);
				metaCGOptions2 = findNextReferenceCPOptions(spline, endTF, out cp2);
				float num = metaCGOptions2.FirstU;
				float definedSecondU = metaCGOptions.GetDefinedSecondU(0f);
				float num2;
				if (spline.FirstVisibleControlPoint == cp2)
				{
					num2 = (data.SourceF[data.Count - 1] * spline.Length - cp.Distance) / (spline.Length - cp.Distance);
					if (metaCGOptions2.UVEdge)
					{
						num = metaCGOptions2.FirstU;
					}
					else if (ext.Count > 1)
					{
						SamplePointUData samplePointUData2 = ext[ext.Count - 1];
						float f;
						if (samplePointUData2.UVEdge)
						{
							SamplePointUData samplePointUData3 = ext[ext.Count - 1];
							f = samplePointUData3.SecondU;
						}
						else
						{
							SamplePointUData samplePointUData4 = ext[ext.Count - 1];
							f = samplePointUData4.FirstU;
						}
						num = Mathf.FloorToInt(f) + 1;
					}
					else
					{
						num = 1f;
					}
				}
				else
				{
					num2 = (data.SourceF[data.Count - 1] * spline.Length - cp.Distance) / (cp2.Distance - cp.Distance);
				}
				ext.Add(new SamplePointUData(data.Count - 1, uvEdge: false, num2 * (num - definedSecondU) + definedSecondU, 0f));
			}
			float num3 = 0f;
			SamplePointUData samplePointUData5 = ext[0];
			float num4;
			if (samplePointUData5.UVEdge)
			{
				SamplePointUData samplePointUData6 = ext[0];
				num4 = samplePointUData6.SecondU;
			}
			else
			{
				SamplePointUData samplePointUData7 = ext[0];
				num4 = samplePointUData7.FirstU;
			}
			float num5 = num4;
			SamplePointUData samplePointUData8 = ext[1];
			float firstU = samplePointUData8.FirstU;
			float[] f2 = data.F;
			SamplePointUData samplePointUData9 = ext[1];
			float num6 = f2[samplePointUData9.Vertex];
			float[] f3 = data.F;
			SamplePointUData samplePointUData10 = ext[0];
			float num7 = num6 - f3[samplePointUData10.Vertex];
			int num8 = 1;
			for (int i = 0; i < data.Count - 1; i++)
			{
				float num9 = (data.F[i] - num3) / num7;
				data.Map[i] = (firstU - num5) * num9 + num5;
				SamplePointUData samplePointUData11 = ext[num8];
				if (samplePointUData11.Vertex != i)
				{
					continue;
				}
				SamplePointUData samplePointUData12 = ext[num8];
				float firstU2 = samplePointUData12.FirstU;
				SamplePointUData samplePointUData13 = ext[num8 + 1];
				if (firstU2 == samplePointUData13.FirstU)
				{
					SamplePointUData samplePointUData14 = ext[num8];
					float num10;
					if (samplePointUData14.UVEdge)
					{
						SamplePointUData samplePointUData15 = ext[num8];
						num10 = samplePointUData15.SecondU;
					}
					else
					{
						SamplePointUData samplePointUData16 = ext[num8];
						num10 = samplePointUData16.FirstU;
					}
					num5 = num10;
					num8++;
				}
				else
				{
					SamplePointUData samplePointUData17 = ext[num8];
					num5 = samplePointUData17.FirstU;
				}
				SamplePointUData samplePointUData18 = ext[num8 + 1];
				firstU = samplePointUData18.FirstU;
				float[] f4 = data.F;
				SamplePointUData samplePointUData19 = ext[num8 + 1];
				float num11 = f4[samplePointUData19.Vertex];
				float[] f5 = data.F;
				SamplePointUData samplePointUData20 = ext[num8];
				num7 = num11 - f5[samplePointUData20.Vertex];
				num3 = data.F[i];
				num8++;
			}
			float[] map = data.Map;
			int num12 = data.Count - 1;
			SamplePointUData samplePointUData21 = ext[ext.Count - 1];
			map[num12] = samplePointUData21.FirstU;
		}

		private static MetaCGOptions findPreviousReferenceCPOptions(CurvySpline spline, float tf, out CurvySplineSegment cp)
		{
			cp = spline.TFToSegment(tf);
			MetaCGOptions metadata;
			do
			{
				metadata = cp.GetMetadata<MetaCGOptions>(autoCreate: true);
				if (spline.FirstVisibleControlPoint == cp)
				{
					return metadata;
				}
				cp = spline.GetPreviousSegment(cp);
			}
			while ((bool)cp && !metadata.UVEdge && !metadata.ExplicitU && !metadata.HasDifferentMaterial);
			return metadata;
		}

		private static MetaCGOptions findNextReferenceCPOptions(CurvySpline spline, float tf, out CurvySplineSegment cp)
		{
			cp = spline.TFToSegment(tf, out float _);
			MetaCGOptions metadata;
			do
			{
				cp = spline.GetNextControlPoint(cp);
				metadata = cp.GetMetadata<MetaCGOptions>(autoCreate: true);
				if (!spline.Closed && spline.LastVisibleControlPoint == cp)
				{
					return metadata;
				}
			}
			while (!metadata.UVEdge && !metadata.ExplicitU && !metadata.HasDifferentMaterial && !(spline.FirstSegment == cp));
			return metadata;
		}
	}
}
